using System.Collections;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using Spine.Unity;
using UnityEngine;
using System.Threading;
using UnityEngine.Events;

public static class MethodExtension
{
    private static Dictionary<IAnimationStateComponent, Dictionary<int, CancellationTokenSource>> _tokenDict = new ();

    private static CancellationTokenSource GetTokenSource(IAnimationStateComponent spine, int index)
    {
        if (_tokenDict.TryGetValue(spine, out var _tokens))
        {
            if (_tokens.TryGetValue(index, out var tokenSource))
            {
                return tokenSource;
            }
        }

        return null;
    }

    public static CancellationTokenSource NewTokenSource(IAnimationStateComponent spine, int index)
    {
        GetTokenSource(spine, index)?.Cancel();
        var tokenSource = new CancellationTokenSource();

        if (!_tokenDict.ContainsKey(spine))
        {
            _tokenDict.Add(spine, new Dictionary<int, CancellationTokenSource>());
        }
        _tokenDict[spine][index] = tokenSource;
        
        return tokenSource;
    }

    public static float mixDuration = 0.25f;
    public static float mixEmptyDuration = 0.15f;
    
    public static async UniTask PlayOnce(this IAnimationStateComponent spine, int index, string animationName, string nextAnimation,bool setEmptyBefore)
    {
        if (string.IsNullOrEmpty(animationName))
        {
            spine.AnimationState.SetEmptyAnimation(index,mixDuration);
            return;
        }

        if (setEmptyBefore)
        {
            spine.AnimationState.SetEmptyAnimation(index, mixEmptyDuration);
        }
        spine.AnimationState.AddAnimation(index, animationName, false,mixDuration);
        
        float animationDuration = spine.AnimationState.GetCurrent(index).Animation.Duration;
        var token = NewTokenSource(spine, index);
        await UniTask.WaitForSeconds(animationDuration, cancellationToken: token.Token);
        if (!string.IsNullOrEmpty(nextAnimation))
        {
            spine.AnimationState.SetAnimation(index, nextAnimation, true);
        }
        else
        {
            spine.AnimationState.SetEmptyAnimation(index,mixDuration);
        }
    }

    public static void PlayLoop(this IAnimationStateComponent spine, int index, string animationName,bool setEmptyBefore)
    {
        GetTokenSource(spine,index)?.Cancel();
        if (setEmptyBefore)
        {
            spine.AnimationState.SetEmptyAnimation(index, mixEmptyDuration);
        }
        spine.AnimationState.AddAnimation(index, animationName, true,mixDuration);
    }

    public static async UniTask OnComplete(this UniTask task, UnityAction call)
    {
        await task;
        call?.Invoke();
    }
}